+use std::cell::RefCell;
use std::collections::HashMap;
use core::{Source, SourceId, SourceMap, Summary, Dependency, PackageId, Package};
/// See also `core::Source`.
pub trait Registry {
/// Attempt to find the packages that match a dependency request.
- fn query(&mut self, name: &Dependency) -> CargoResult<Vec<Summary>>;
+ fn query(&mut self,
+ dep: &Dependency,
+ f: &mut FnMut(Summary)) -> CargoResult<()>;
+
+ fn query_vec(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
+ let mut ret = Vec::new();
+ self.query(dep, &mut |s| ret.push(s))?;
+ Ok(ret)
+ }
/// Returns whether or not this registry will return summaries with
/// checksums listed.
}
impl Registry for Vec<Summary> {
- fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
- Ok(self.iter().filter(|summary| dep.matches(*summary))
- .cloned().collect())
+ fn query(&mut self,
+ dep: &Dependency,
+ f: &mut FnMut(Summary)) -> CargoResult<()> {
+ for summary in self.iter().filter(|summary| dep.matches(*summary)) {
+ f(summary.clone());
+ }
+ Ok(())
}
}
impl Registry for Vec<Package> {
- fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
- Ok(self.iter().filter(|pkg| dep.matches(pkg.summary()))
- .map(|pkg| pkg.summary().clone()).collect())
+ fn query(&mut self,
+ dep: &Dependency,
+ f: &mut FnMut(Summary)) -> CargoResult<()> {
+ for summary in self.iter()
+ .map(|p| p.summary())
+ .filter(|summary| dep.matches(*summary)) {
+ f(summary.clone());
+ }
+ Ok(())
}
}
impl<'a, T: ?Sized + Registry + 'a> Registry for Box<T> {
- fn query(&mut self, name: &Dependency) -> CargoResult<Vec<Summary>> {
- (**self).query(name)
+ fn query(&mut self,
+ dep: &Dependency,
+ f: &mut FnMut(Summary)) -> CargoResult<()> {
+ (**self).query(dep, f)
}
}
/// a `Source`. Each `Source` in the map has been updated (using network
/// operations if necessary) and is ready to be queried for packages.
pub struct PackageRegistry<'cfg> {
- sources: SourceMap<'cfg>,
+ sources: RefCell<SourceMap<'cfg>>,
// A list of sources which are considered "overrides" which take precedent
// when querying for packages.
pub fn new(config: &'cfg Config) -> CargoResult<PackageRegistry<'cfg>> {
let source_config = SourceConfigMap::new(config)?;
Ok(PackageRegistry {
- sources: SourceMap::new(),
+ sources: RefCell::new(SourceMap::new()),
source_ids: HashMap::new(),
overrides: Vec::new(),
source_config: source_config,
}
pub fn get(self, package_ids: &[PackageId]) -> PackageSet<'cfg> {
- trace!("getting packages; sources={}", self.sources.len());
- PackageSet::new(package_ids, self.sources)
+ let sources = self.sources.into_inner();
+ trace!("getting packages; sources={}", sources.len());
+ PackageSet::new(package_ids, sources)
}
fn ensure_loaded(&mut self, namespace: &SourceId, kind: Kind) -> CargoResult<()> {
fn add_source(&mut self, source: Box<Source + 'cfg>, kind: Kind) {
let id = source.source_id().clone();
- self.sources.insert(source);
+ self.sources.get_mut().insert(source);
self.source_ids.insert(id.clone(), (id, kind));
}
// Ensure the source has fetched all necessary remote data.
let _p = profile::start(format!("updating: {}", source_id));
- self.sources.get_mut(source_id).unwrap().update()
+ self.sources.get_mut().get_mut(source_id).unwrap().update()
})().chain_err(|| format!("Unable to update {}", source_id))
}
fn query_overrides(&mut self, dep: &Dependency)
-> CargoResult<Option<Summary>> {
for s in self.overrides.iter() {
- let src = self.sources.get_mut(s).unwrap();
+ let src = self.sources.get_mut().get_mut(s).unwrap();
let dep = Dependency::new_override(dep.name(), s);
- let mut results = src.query(&dep)?;
+ let mut results = src.query_vec(&dep)?;
if results.len() > 0 {
return Ok(Some(results.remove(0)))
}
}
impl<'cfg> Registry for PackageRegistry<'cfg> {
- fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
+ fn query(&mut self,
+ dep: &Dependency,
+ f: &mut FnMut(Summary)) -> CargoResult<()> {
// Ensure the requested source_id is loaded
self.ensure_loaded(dep.source_id(), Kind::Normal).chain_err(|| {
format!("failed to load source for a dependency \
on `{}`", dep.name())
})?;
+ // Look for an override and get ready to query the real source
let override_summary = self.query_overrides(&dep)?;
- let real_summaries = match self.sources.get_mut(dep.source_id()) {
- Some(src) => Some(src.query(&dep)?),
- None => None,
+ let mut sources = self.sources.borrow_mut();
+ let source = match sources.get_mut(dep.source_id()) {
+ Some(src) => src,
+ None => {
+ if override_summary.is_some() {
+ bail!("override found but no real ones");
+ }
+ return Ok(())
+ }
};
- let ret = match (override_summary, real_summaries) {
- (Some(candidate), Some(summaries)) => {
- if summaries.len() != 1 {
- bail!("found an override with a non-locked list");
- }
- self.warn_bad_override(&candidate, &summaries[0])?;
- vec![candidate]
+ // Query the real source, keeping track of some extra info. If we've got
+ // an override we don't actually ship up summaries. If we do ship up
+ // summaries though we be sure to postprocess them to a locked version
+ // to assist with lockfiles and conservative updates.
+ let mut n = 0;
+ let mut to_warn = None;
+ source.query(dep, &mut |summary| {
+ n += 1;
+ if override_summary.is_none() {
+ f(self.lock(summary))
+ } else {
+ to_warn = Some(summary);
}
- (Some(_), None) => bail!("override found but no real ones"),
- (None, Some(summaries)) => summaries,
- (None, None) => Vec::new(),
+ })?;
+
+ // After all that's said and done we need to check the override summary
+ // itself. If present we'll do some more validation and yield it up,
+ // otherwise we're done.
+ let override_summary = match override_summary {
+ Some(s) => s,
+ None => return Ok(())
};
- // post-process all returned summaries to ensure that we lock all
- // relevant summaries to the right versions and sources
- Ok(ret.into_iter().map(|summary| self.lock(summary)).collect())
+ if n > 1 {
+ bail!("found an override with a non-locked list");
+ } else if let Some(summary) = to_warn {
+ self.warn_bad_override(&override_summary, &summary)?;
+ }
+ f(self.lock(override_summary));
+ Ok(())
}
}
}
impl Registry for RegistryBuilder {
- fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
+ fn query(&mut self,
+ dep: &Dependency,
+ f: &mut FnMut(Summary)) -> CargoResult<()> {
debug!("querying; dep={:?}", dep);
let overrides = self.query_overrides(dep);
if overrides.is_empty() {
- self.summaries.query(dep)
+ self.summaries.query(dep, f)
} else {
- Ok(overrides)
+ for s in overrides {
+ f(s);
+ }
+ Ok(())
}
}
}
let all_req = semver::VersionReq::parse("*").unwrap();
let mut new_dep = dep.clone();
new_dep.set_version_req(all_req);
- let mut candidates = match registry.query(&new_dep) {
+ let mut candidates = match registry.query_vec(&new_dep) {
Ok(candidates) => candidates,
Err(e) => return e,
};
fn query(&self,
registry: &mut Registry,
dep: &Dependency) -> CargoResult<Vec<Candidate>> {
- let summaries = registry.query(dep)?;
- summaries.into_iter().map(|summary| {
- // get around lack of non-lexical lifetimes
- let summary2 = summary.clone();
+ let mut ret = Vec::new();
+ registry.query(dep, &mut |s| {
+ ret.push(Candidate { summary: s, replace: None });
+ })?;
+ for candidate in ret.iter_mut() {
+ let summary = &candidate.summary;
let mut potential_matches = self.replacements.iter()
- .filter(|&&(ref spec, _)| spec.matches(summary2.package_id()));
+ .filter(|&&(ref spec, _)| spec.matches(summary.package_id()));
let &(ref spec, ref dep) = match potential_matches.next() {
- None => return Ok(Candidate { summary: summary, replace: None }),
+ None => continue,
Some(replacement) => replacement,
};
debug!("found an override for {} {}", dep.name(), dep.version_req());
- let mut summaries = registry.query(dep)?.into_iter();
+ let mut summaries = registry.query_vec(dep)?.into_iter();
let s = summaries.next().ok_or_else(|| {
format!("no matching package for override `{}` found\n\
location searched: {}\n\
debug!("\t{} => {}", dep.name(), dep.version_req());
}
- Ok(Candidate { summary: summary, replace: replace })
- }).collect()
+ candidate.replace = replace;
+ }
+ Ok(ret)
}
fn prev_active(&self, dep: &Dependency) -> &[Summary] {
use serde_json;
use core::dependency::{Dependency, DependencyInner, Kind};
-use core::{SourceId, Summary, PackageId, Registry};
+use core::{SourceId, Summary, PackageId};
use sources::registry::{RegistryPackage, RegistryDependency, INDEX_LOCK};
use sources::registry::RegistryData;
use util::{CargoError, CargoResult, internal, Filesystem, Config};
pub fn query(&mut self,
dep: &Dependency,
- load: &mut RegistryData)
- -> CargoResult<Vec<Summary>> {
- let mut summaries = {
- let summaries = self.summaries(dep.name(), load)?;
- summaries.iter().filter(|&&(_, yanked)| {
- dep.source_id().precise().is_some() || !yanked
- }).map(|s| s.0.clone()).collect::<Vec<_>>()
- };
+ load: &mut RegistryData,
+ f: &mut FnMut(Summary))
+ -> CargoResult<()> {
+ let source_id = self.source_id.clone();
+ let summaries = self.summaries(dep.name(), load)?;
+ let summaries = summaries.iter().filter(|&&(_, yanked)| {
+ dep.source_id().precise().is_some() || !yanked
+ }).map(|s| s.0.clone());
// Handle `cargo update --precise` here. If specified, our own source
// will have a precise version listed of the form `<pkg>=<req>` where
// `<pkg>` is the name of a crate on this source and `<req>` is the
// version requested (agument to `--precise`).
- summaries.retain(|s| {
- match self.source_id.precise() {
+ let summaries = summaries.filter(|s| {
+ match source_id.precise() {
Some(p) if p.starts_with(dep.name()) &&
p[dep.name().len()..].starts_with('=') => {
let vers = &p[dep.name().len() + 1..];
_ => true,
}
});
- summaries.query(dep)
+
+ for summary in summaries {
+ if dep.matches(&summary) {
+ f(summary);
+ }
+ }
+ Ok(())
}
}